package utils

import (
	"gogo/log"
	"reflect"
	"strconv"
	"strings"

	e "github.com/rbrahul/exception"
	"go.mongodb.org/mongo-driver/bson"
)

func (c *GoGo_Utils_Class) GetFloat64(value interface{}) float64 {
	if value != nil {
		switch vv := value.(type) {
		case int:
			return float64(vv)
		case int8:
			return float64(vv)
		case int16:
			return float64(vv)
		case int32:
			return float64(vv)
		case int64:
			return float64(vv)
		case uint:
			return float64(vv)
		case uint8:
			return float64(vv)
		case uint16:
			return float64(vv)
		case uint32:
			return float64(vv)
		case uint64:
			return float64(vv)
		case float32:
			return float64(vv)
		case float64:
			return vv
		case string:
			num, _ := strconv.ParseFloat(vv, 64)
			return num
		}
	}

	return 0
}

func (c *GoGo_Utils_Class) checkInterface(src_v, dst_v interface{}) bool {

	reflect_TypeOf_src_v := reflect.TypeOf(src_v).Name()
	reflect_TypeOf_dst_v := reflect.TypeOf(dst_v).Name()

	src_v_array, src_v_array_ok := src_v.([]interface{})
	if !src_v_array_ok {
		src_v_array, src_v_array_ok = src_v.(bson.A)
	}

	dst_v_array, dst_v_array_ok := dst_v.([]interface{})
	if !dst_v_array_ok {
		dst_v_array, dst_v_array_ok = dst_v.(bson.A)
	}

	if src_v_array_ok && dst_v_array_ok {
		if len(src_v_array) != len(dst_v_array) {
			return false
		}

		for i := 0; i < len(src_v_array); i++ {
			if !c.checkInterface(src_v_array[i], dst_v_array[i]) {
				return false
			}
		}

		goto RETURN_TRUE
	}

	if reflect_TypeOf_src_v == "" || reflect_TypeOf_dst_v == "" {
		return false
	}

	if reflect_TypeOf_src_v == reflect_TypeOf_dst_v { //如果两个类型一样
		src_v_map, src_v_map_ok := src_v.(map[string]interface{})
		dst_v_map, dst_v_map_ok := dst_v.(map[string]interface{})
		if src_v_map_ok && dst_v_map_ok {
			if !c.CheckMapInterface(src_v_map, dst_v_map) {
				return false
			}
			goto RETURN_TRUE
		}

		if src_v != dst_v {
			return false
		}

	} else { //如果两个类型不一样
		if reflect_TypeOf_src_v == "float64" && reflect_TypeOf_dst_v != "string" {
			if src_v.(float64) != c.GetFloat64(dst_v) {
				return false
			}

		} else if reflect_TypeOf_dst_v == "float64" && reflect_TypeOf_src_v != "string" {
			if dst_v.(float64) != c.GetFloat64(src_v) {
				return false
			}
		} else if reflect_TypeOf_dst_v == "int64" && reflect_TypeOf_src_v != "string" {
			if dst_v.(int64) != int64(c.GetFloat64(src_v)) {
				return false
			}
		} else {
			log.This().ErrorF("checkInterface: %s %s", reflect_TypeOf_src_v, reflect_TypeOf_dst_v)
		}
	}

RETURN_TRUE:
	return true
}

func (c *GoGo_Utils_Class) checkMapInterface2(src, dst map[string]interface{}) bool {
	if src == nil || dst == nil {
		return false
	}

	for k, src_v := range src {
		if strings.HasPrefix(k, "_") || strings.HasPrefix(k, "@") {
			continue
		}

		dst_v, ok := dst[k]
		if !ok {
			return false
		}

		if !c.checkInterface(src_v, dst_v) {
			return false
		}
	}

	for k, dst_v := range dst {
		if strings.HasPrefix(k, "_") || strings.HasPrefix(k, "@") {
			continue
		}

		src_v, ok := src[k]
		if !ok {
			return false
		}

		if !c.checkInterface(dst_v, src_v) {
			return false
		}
	}

	return true
}

func (c *GoGo_Utils_Class) CheckMapInterface(src, dst map[string]interface{}) bool {
	ret := false

	e.Try(func() {
		ret = c.checkMapInterface2(src, dst)
	}).Catch(nil, func(excep *e.Exception) {
		log.This().ErrorF("CheckMapInterface Error: %s", excep.Message)
	}).Run()

	return ret
}
